﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
using Orange.Logistics.Infrastructure;
using Orange.Logistics.Models;
using Orange.Logistics.Services;

namespace Orange.Logistics.Controllers {
    [Permission]
    public abstract class BaseController<T> : System.Web.Mvc.Controller where T : class {
        private readonly IBaseService<T> service;
        protected Pager PG { get; set; }

        public object[] Keys {
            get {
                var keys = TempData["Keys"] as object[];
                if (keys == null) {
                    throw new Exception("Keys not exists!");
                }
                return keys;
            }
            set { TempData["Keys"] = value; }
        }

        public BaseController(IBaseService<T> service) {
            this.service = service;
        }

        private enum SubmitAction {
            Create,
            Update,
            Delete
        }

        public UserInfo CurrentUser {
            get {
                if (Session["CurrentUserInfo"] == null) {
                    throw new Exception("当前用户信息丢失");
                }
                return Session["CurrentUserInfo"] as UserInfo;
            }
            set { Session["CurrentUserInfo"] = value; }
        }

        public ActionResult Index() {
            return View();
        }

        protected void InitPager() {
            PG = new Pager() {
                pageNo = Convert.ToInt32(Request["page"]),
                pageSize = Convert.ToInt32(Request["pagesize"]),
                sort = Request["sortname"],
                asc = Request["sortorder"] != "desc",
                where = Request["where"],
                parms = Request["p"],
            };
        }

        public virtual JsonResult GetGrid() {
            InitPager();
            var list = service.List(null);
            int total = list.Count();
            IEnumerable<T> source = null;
            if (PG.asc) {
                source = list.OrderBy(GetOrderBy(PG.sort));
            } else {
                source = list.OrderByDescending(GetOrderBy(PG.sort));
            }
            return Json(new { Rows = PagedList<T>(source), Total = total });
        }

        //private string GetTableName() {
        //    Type t = typeof(T);
        //    var attributes = t.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.TableAttribute), false);
        //    if (attributes.Length == 0) {
        //        return t.Name + "s";
        //    } else {
        //        return (attributes[0] as System.ComponentModel.DataAnnotations.TableAttribute).Name;
        //    }
        //}

        public JsonResult Get() {
            var k = Keys;
            Keys = k;
            var model = service.Find(k);
            return Json(model, JsonRequestBehavior.AllowGet);
        }

        public ActionResult Create() {
            ViewBag.Action = "C";
            return View("Form");
        }

        [HttpPost]
        public virtual JsonResult Create(T model) {
            try {
                SetModelProperties(model, SubmitAction.Create);
                service.Add(model);
                service.SaveChanges();
                return Json(true);
            } catch { }
            return Json(false);
        }

        public virtual ActionResult Detail() {
            ViewBag.Action = "R";
            Keys = GetKeys(Request["keys"]);
            return View("Form");
        }

        private object[] GetKeys(string keys) {
            if (string.IsNullOrEmpty(keys)) {
                throw new ArgumentException("keys are empty.");
            }
            int id;
            if (int.TryParse(keys, out id)) {
                return new object[] { id };
            }
            return keys.Split('&').Cast<object[]>().ToArray();
        }

        public virtual ActionResult Update() {
            ViewBag.Action = "U";
            Keys = GetKeys(Request["keys"]);
            return View("Form");
        }

        [HttpPost]
        public virtual JsonResult Update(FormCollection forms) {
            var model = service.Find(Keys);
            if (TryUpdateModel(model)) {
                SetModelProperties(model, SubmitAction.Update);
                service.Update(model);
                service.SaveChanges();
                return Json(true);
            }
            return Json(false);
        }

        //Sunny start
      
        //Sunny end

        [HttpPost]
        public JsonResult Delete() {
            try {
                string curUser = CurrentUser.UserId;
                DateTime curtime = DateTime.Now;
                List<T> models = JsonConvert.DeserializeObject<List<T>>(Request["data"]);
                foreach (var model in models) {
                    SetModelProperties(model, SubmitAction.Delete);
                    service.Update(model);
                }
                service.SaveChanges();
                return Json(true);
            } catch { }
            return Json(false);
        }

        private void SetModelProperties(T model, SubmitAction action) {
            Type t = typeof(T);
            string status = null;
            switch (action) {
                case SubmitAction.Create:
                case SubmitAction.Update:
                    status = "A";
                    break;
                case SubmitAction.Delete:
                    status = "D";
                    break;
                default:
                    break;
            }
            var properties = t.GetProperties();
            foreach (var p in properties) {
                switch (p.Name) {
                    case "Modifytime":
                        p.SetValue(model, DateTime.Now, null);
                        break;
                    case "Modifyuser":
                        p.SetValue(model, CurrentUser.UserId, null);
                        break;
                    case "Status":
                        p.SetValue(model, status, null);
                        break;
                    default:
                        break;
                }
            }
        }

        protected IEnumerable<U> PagedList<U>(IEnumerable<U> source) {
            return source.Skip((PG.pageNo - 1) * PG.pageSize).Take(PG.pageSize);
        }

        protected abstract Func<T, object> GetOrderBy(string sort);


        protected override void Dispose(bool disposing) {
            if (disposing) {
                service.Dispose();
            }
            base.Dispose(disposing);
        }

        public struct Pager {
            public int pageNo;
            public int pageSize;
            public string sort;
            public bool asc;
            public string where;
            public string parms;
        }
    }
}